Exercise 5¶

  1. Get a polygons map of the lowest administrative unit possible.

  2. Get a table of variables for those units. At least 3 numerical variables.

  3. Preprocess both tables and get them ready for merging.

  4. Do the merging, making the changes needed so that you keep the most rows.

In [ ]:
!pip install fiona
Collecting fiona
  Downloading fiona-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (56 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 56.6/56.6 kB 3.7 MB/s eta 0:00:00
Requirement already satisfied: attrs>=19.2.0 in /usr/local/lib/python3.11/dist-packages (from fiona) (25.3.0)
Requirement already satisfied: certifi in /usr/local/lib/python3.11/dist-packages (from fiona) (2025.6.15)
Requirement already satisfied: click~=8.0 in /usr/local/lib/python3.11/dist-packages (from fiona) (8.2.1)
Collecting click-plugins>=1.0 (from fiona)
  Downloading click_plugins-1.1.1.2-py2.py3-none-any.whl.metadata (6.5 kB)
Collecting cligj>=0.5 (from fiona)
  Downloading cligj-0.7.2-py3-none-any.whl.metadata (5.0 kB)
Downloading fiona-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.3/17.3 MB 92.0 MB/s eta 0:00:00
Downloading click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Downloading cligj-0.7.2-py3-none-any.whl (7.1 kB)
Installing collected packages: cligj, click-plugins, fiona
Successfully installed click-plugins-1.1.1.2 cligj-0.7.2 fiona-1.10.1
In [ ]:
# data table
import geopandas as gpd
import os

usaDataLink="https://github.com/Derick047/PC6_Parte2/raw/refs/heads/main/Data%20utilizada/usa_counties/usa_counties.gpkg"
gpd.list_layers(usaDataLink)
Out[ ]:
name geometry_type
0 counties MultiPolygon
In [ ]:
datadisMap = gpd.read_file(usaDataLink, layer='counties')
In [ ]:
datadisMap.info()
<class 'geopandas.geodataframe.GeoDataFrame'>
RangeIndex: 3235 entries, 0 to 3234
Data columns (total 13 columns):
 #   Column      Non-Null Count  Dtype   
---  ------      --------------  -----   
 0   STATEFP     3235 non-null   object  
 1   COUNTYFP    3235 non-null   object  
 2   COUNTYNS    3235 non-null   object  
 3   AFFGEOID    3235 non-null   object  
 4   GEOID       3235 non-null   object  
 5   NAME        3235 non-null   object  
 6   NAMELSAD    3235 non-null   object  
 7   STUSPS      3235 non-null   object  
 8   STATE_NAME  3235 non-null   object  
 9   LSAD        3235 non-null   object  
 10  ALAND       3235 non-null   int64   
 11  AWATER      3235 non-null   int64   
 12  geometry    3235 non-null   geometry
dtypes: geometry(1), int64(2), object(10)
memory usage: 328.7+ KB
In [ ]:
people_url = "https://github.com/Derick047/PC6_Parte2/raw/main/Data%20utilizada/People.csv"
income_url = "https://github.com/Derick047/PC6_Parte2/raw/main/Data%20utilizada/Income.csv"
In [ ]:
people = pd.read_csv(people_url, encoding="ISO-8859-1")
income = pd.read_csv(income_url, encoding="ISO-8859-1")
In [ ]:
# Verificar columnas
print(people.columns)
print(income.columns)
Index(['FIPS', 'State', 'County', 'Attribute', 'Value'], dtype='object')
Index(['FIPS', 'State', 'County', 'Attribute', 'Value'], dtype='object')
In [ ]:
print(people.columns.to_list())
['FIPS', 'State', 'County', 'Attribute', 'Value']
In [ ]:
# Filtrar atributos específicos
poverty = people[people["Attribute"] == "OwnHomePct"].copy()
poverty["Value"] = pd.to_numeric(poverty["Value"], errors="coerce")
poverty = poverty[["FIPS", "Value"]].rename(columns={"Value": "OwnHomePct"})

income = income[income["Attribute"] == "Median_Household_Income_2021"].copy()
income["Value"] = pd.to_numeric(income["Value"], errors="coerce")
income = income[["FIPS", "Value"]].rename(columns={"Value": "MedianIncome"})
In [ ]:
poverty["FIPS"] = poverty["FIPS"].astype(str).str.zfill(5)
income["FIPS"] = income["FIPS"].astype(str).str.zfill(5)

socio = pd.merge(poverty, income, on="FIPS", how="outer")
counties2 = datadisMap.merge(socio, left_on="GEOID", right_on="FIPS", how="left")
In [ ]:
people["Attribute"].unique()
Out[ ]:
array(['Age65AndOlderNum2020', 'Age65AndOlderPct2020',
       'AsianNonHispanicNum2020', 'AsianNonHispanicPct2020', 'AvgHHSize',
       'BlackNonHispanicNum2020', 'BlackNonHispanicPct2020',
       'Ed1LessThanHSNum', 'Ed1LessThanHSPct', 'Ed2HSDiplomaOnlyNum',
       'Ed2HSDiplomaOnlyPct', 'Ed3SomeCollegeNum', 'Ed3SomeCollegePct',
       'Ed4AssocDegreeNum', 'Ed4AssocDegreePct', 'Ed5CollegePlusNum',
       'Ed5CollegePlusPct', 'ESTIMATESBASE2020', 'FemaleHHNum',
       'FemaleHHPct', 'ForeignBornAfricaNum', 'ForeignBornAfricaPct',
       'ForeignBornAsiaNum', 'ForeignBornAsiaPct', 'ForeignBornCaribNum',
       'ForeignBornCaribPct', 'ForeignBornCentralSouthAmNum',
       'ForeignBornCentralSouthAmPct', 'ForeignBornEuropeNum',
       'ForeignBornEuropePct', 'ForeignBornMexNum', 'ForeignBornMexPct',
       'ForeignBornNum', 'ForeignBornPct', 'HH65PlusAloneNum',
       'HH65PlusAlonePct', 'HispanicNum2020', 'HispanicPct2020',
       'HispanicPopChangeRate1020', 'LandAreaSQMiles2020',
       'MultipleRaceNum2020', 'MultipleRacePct2020',
       'MultipleRacePopChangeRate1020',
       'NativeAmericanNonHispanicNum2020',
       'NativeAmericanNonHispanicPct2020',
       'Natural_Change_Rate_2020_2021', 'NaturalChange1019',
       'NaturalChangeRate1019', 'NaturalChg2020_2021',
       'Net_InterMigration_2020_2021', 'Net_InterMigrationRate_2020_2021',
       'Net_International_Migration_2010_2019',
       'Net_International_Migration_Rate_2010_2019',
       'Net_Migration_2020_2021', 'Net_Migration_Rate_2020_2021',
       'NetMigration1019', 'NetMigrationRate1019', 'NonEnglishHHNum',
       'NonEnglishHHPct', 'NonHispAsianPopChangeRate1020',
       'NonHispBlackPopChangeRate1020', 'NonHispNatAmerPopChangeRate1020',
       'NonHispWhitePopChangeRate1020', 'OwnHomeNum', 'OwnHomePct',
       'Pop_change_Rate_2020_2021', 'PopChangeRate1019',
       'PopChangeRate1020', 'PopDensity2020', 'POPESTIMATE2020',
       'POPESTIMATE2021', 'TotalHH', 'TotalOccHU', 'TotalPop2020',
       'TotalPop25Plus', 'TotalPopACS', 'TotalPopEst2010',
       'TotalPopEst2011', 'TotalPopEst2012', 'TotalPopEst2013',
       'TotalPopEst2014', 'TotalPopEst2015', 'TotalPopEst2016',
       'TotalPopEst2017', 'TotalPopEst2018', 'TotalPopEst2019',
       'TotalPopEstBase2010', 'Under18Num2020', 'Under18Pct2020',
       'WhiteNonHispanicNum2020', 'WhiteNonHispanicPct2020'], dtype=object)
In [ ]:
own_home_df = people[people["Attribute"] == "OwnHomePct"].copy()
own_home_df["Value"] = pd.to_numeric(own_home_df["Value"], errors="coerce")
In [ ]:
import seaborn as sea
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
sea.histplot(own_home_df["Value"], color='green', bins=30)
plt.title("Distribución de hogares con vivienda propia en EE.UU.")
plt.xlabel("Porcentaje (%)")
plt.ylabel("Frecuencia")
plt.grid(True)
plt.show()
No description has been provided for this image
In [ ]:
import geopandas as gpd
import pandas as pd

# Leer shapefile de condados
usa_link = "https://github.com/Derick047/PC6_Parte2/raw/main/Data%20utilizada/usa_counties/usa_counties.gpkg"
counties = gpd.read_file(usa_link, layer="counties")
counties["GEOID"] = counties["GEOID"].astype(str)
In [ ]:
counties2.columns.to_list()
Out[ ]:
['STATEFP',
 'COUNTYFP',
 'COUNTYNS',
 'AFFGEOID',
 'GEOID',
 'NAME',
 'NAMELSAD',
 'STUSPS',
 'STATE_NAME',
 'LSAD',
 'ALAND',
 'AWATER',
 'geometry',
 'FIPS',
 'OwnHomePct',
 'MedianIncome']
In [ ]:
!pip install folium matplotlib mapclassify
Requirement already satisfied: folium in /usr/local/lib/python3.11/dist-packages (0.19.7)
Requirement already satisfied: matplotlib in /usr/local/lib/python3.11/dist-packages (3.10.0)
Collecting mapclassify
  Downloading mapclassify-2.9.0-py3-none-any.whl.metadata (3.1 kB)
Requirement already satisfied: branca>=0.6.0 in /usr/local/lib/python3.11/dist-packages (from folium) (0.8.1)
Requirement already satisfied: jinja2>=2.9 in /usr/local/lib/python3.11/dist-packages (from folium) (3.1.6)
Requirement already satisfied: numpy in /usr/local/lib/python3.11/dist-packages (from folium) (2.0.2)
Requirement already satisfied: requests in /usr/local/lib/python3.11/dist-packages (from folium) (2.32.3)
Requirement already satisfied: xyzservices in /usr/local/lib/python3.11/dist-packages (from folium) (2025.4.0)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (1.3.2)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (4.58.4)
Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (1.4.8)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (24.2)
Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (11.2.1)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (3.2.3)
Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib) (2.9.0.post0)
Requirement already satisfied: networkx>=3.2 in /usr/local/lib/python3.11/dist-packages (from mapclassify) (3.5)
Requirement already satisfied: pandas>=2.1 in /usr/local/lib/python3.11/dist-packages (from mapclassify) (2.2.2)
Requirement already satisfied: scikit-learn>=1.4 in /usr/local/lib/python3.11/dist-packages (from mapclassify) (1.6.1)
Requirement already satisfied: scipy>=1.12 in /usr/local/lib/python3.11/dist-packages (from mapclassify) (1.15.3)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.11/dist-packages (from jinja2>=2.9->folium) (3.0.2)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas>=2.1->mapclassify) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas>=2.1->mapclassify) (2025.2)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.7->matplotlib) (1.17.0)
Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.4->mapclassify) (1.5.1)
Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.4->mapclassify) (3.6.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests->folium) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests->folium) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests->folium) (2.4.0)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests->folium) (2025.6.15)
Downloading mapclassify-2.9.0-py3-none-any.whl (286 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 286.7/286.7 kB 14.7 MB/s eta 0:00:00
Installing collected packages: mapclassify
Successfully installed mapclassify-2.9.0
In [ ]:
counties2.explore(
    column="OwnHomePct",
    scheme="fisherjenks",
    legend=True,
    tooltip=False,
    popup=["NAME", "STATE_NAME", "OwnHomePct"],
    legend_kwds=dict(colorbar=False),
    cmap="Greens"
)
Out[ ]:
Make this Notebook Trusted to load map: File -> Trust Notebook
  1. Compute the neighbors of the capital city of your country. Plot the results for each of the options.
In [ ]:
from libpysal.weights import Queen, Rook, KNN

# Crear pesos espaciales
w_rook = Rook.from_dataframe(datadisMap)
w_queen = Queen.from_dataframe(datadisMap)
w_knn8 = KNN.from_dataframe(datadisMap, k=8)
/tmp/ipython-input-32-2456757846.py:4: FutureWarning: `use_index` defaults to False but will default to True in future. Set True/False directly to control this behavior and silence this warning
  w_rook = Rook.from_dataframe(datadisMap)
/usr/local/lib/python3.11/dist-packages/libpysal/weights/contiguity.py:61: UserWarning: The weights matrix is not fully connected: 
 There are 26 disconnected components.
 There are 21 islands with ids: 290, 291, 470, 471, 746, 754, 917, 918, 919, 1023, 1047, 1116, 1137, 1286, 1479, 1506, 1644, 1702, 2758, 2946, 3210.
  W.__init__(self, neighbors, ids=ids, **kw)
/tmp/ipython-input-32-2456757846.py:5: FutureWarning: `use_index` defaults to False but will default to True in future. Set True/False directly to control this behavior and silence this warning
  w_queen = Queen.from_dataframe(datadisMap)
/usr/local/lib/python3.11/dist-packages/libpysal/weights/contiguity.py:347: UserWarning: The weights matrix is not fully connected: 
 There are 26 disconnected components.
 There are 21 islands with ids: 290, 291, 470, 471, 746, 754, 917, 918, 919, 1023, 1047, 1116, 1137, 1286, 1479, 1506, 1644, 1702, 2758, 2946, 3210.
  W.__init__(self, neighbors, ids=ids, **kw)
/usr/local/lib/python3.11/dist-packages/libpysal/weights/distance.py:153: UserWarning: The weights matrix is not fully connected: 
 There are 3 disconnected components.
  W.__init__(self, neighbors, id_order=ids, **kwargs)
In [ ]:
# Revisar islas (condados sin vecinos contiguos)
print("Islas en Queen:", w_queen.islands)

# Encontrar índice del condado de Washington D.C.
idx_dc = datadisMap[datadisMap['NAME'] == "District of Columbia"].index[0]
Islas en Queen: [290, 291, 470, 471, 746, 754, 917, 918, 919, 1023, 1047, 1116, 1137, 1286, 1479, 1506, 1644, 1702, 2758, 2946, 3210]
In [ ]:
# Visualizar vecinos con Rook
import matplotlib.pyplot as plt

neighbors_rook = w_rook.neighbors[idx_dc]
base = datadisMap.iloc[neighbors_rook].plot(color='yellow', edgecolor='black')
datadisMap.loc[[idx_dc]].plot(ax=base, color='red', edgecolor='black')
plt.title("Vecinos de Washington D.C. (Rook)")
plt.axis("off")
plt.show()
No description has been provided for this image
    • Compute the Moran's coefficient for one of your three numeric variables.

    • Make a scatter plot for each variable.

In [ ]:
!pip install esda splot libpysal geopandas mapclassify
Collecting esda
  Downloading esda-2.7.0-py3-none-any.whl.metadata (2.0 kB)
Collecting splot
  Downloading splot-1.1.7-py3-none-any.whl.metadata (8.9 kB)
Requirement already satisfied: libpysal in /usr/local/lib/python3.11/dist-packages (4.13.0)
Requirement already satisfied: geopandas in /usr/local/lib/python3.11/dist-packages (1.0.1)
Requirement already satisfied: mapclassify in /usr/local/lib/python3.11/dist-packages (2.9.0)
Requirement already satisfied: numpy>=1.24 in /usr/local/lib/python3.11/dist-packages (from esda) (2.0.2)
Requirement already satisfied: pandas>1.5 in /usr/local/lib/python3.11/dist-packages (from esda) (2.2.2)
Requirement already satisfied: scikit-learn>=1.2 in /usr/local/lib/python3.11/dist-packages (from esda) (1.6.1)
Requirement already satisfied: scipy>=1.9 in /usr/local/lib/python3.11/dist-packages (from esda) (1.15.3)
Requirement already satisfied: shapely>=2.0 in /usr/local/lib/python3.11/dist-packages (from esda) (2.1.1)
Collecting giddy (from splot)
  Downloading giddy-2.3.6-py3-none-any.whl.metadata (6.3 kB)
Requirement already satisfied: matplotlib>=3.3.3 in /usr/local/lib/python3.11/dist-packages (from splot) (3.10.0)
Requirement already satisfied: packaging in /usr/local/lib/python3.11/dist-packages (from splot) (24.2)
Requirement already satisfied: seaborn>=0.11.0 in /usr/local/lib/python3.11/dist-packages (from splot) (0.13.2)
Collecting spreg (from splot)
  Downloading spreg-1.8.3-py3-none-any.whl.metadata (1.7 kB)
Requirement already satisfied: beautifulsoup4>=4.10 in /usr/local/lib/python3.11/dist-packages (from libpysal) (4.13.4)
Requirement already satisfied: platformdirs>=2.0.2 in /usr/local/lib/python3.11/dist-packages (from libpysal) (4.3.8)
Requirement already satisfied: requests>=2.27 in /usr/local/lib/python3.11/dist-packages (from libpysal) (2.32.3)
Requirement already satisfied: pyogrio>=0.7.2 in /usr/local/lib/python3.11/dist-packages (from geopandas) (0.11.0)
Requirement already satisfied: pyproj>=3.3.0 in /usr/local/lib/python3.11/dist-packages (from geopandas) (3.7.1)
Requirement already satisfied: networkx>=3.2 in /usr/local/lib/python3.11/dist-packages (from mapclassify) (3.5)
Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.11/dist-packages (from beautifulsoup4>=4.10->libpysal) (2.7)
Requirement already satisfied: typing-extensions>=4.0.0 in /usr/local/lib/python3.11/dist-packages (from beautifulsoup4>=4.10->libpysal) (4.14.0)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (1.3.2)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (4.58.4)
Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (1.4.8)
Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (11.2.1)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (3.2.3)
Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas>1.5->esda) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas>1.5->esda) (2025.2)
Requirement already satisfied: certifi in /usr/local/lib/python3.11/dist-packages (from pyogrio>=0.7.2->geopandas) (2025.6.15)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->libpysal) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->libpysal) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->libpysal) (2.4.0)
Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.2->esda) (1.5.1)
Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.2->esda) (3.6.0)
Collecting quantecon>=0.7 (from giddy->splot)
  Downloading quantecon-0.8.1-py3-none-any.whl.metadata (5.2 kB)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.7->matplotlib>=3.3.3->splot) (1.17.0)
Requirement already satisfied: numba>=0.49.0 in /usr/local/lib/python3.11/dist-packages (from quantecon>=0.7->giddy->splot) (0.60.0)
Requirement already satisfied: sympy in /usr/local/lib/python3.11/dist-packages (from quantecon>=0.7->giddy->splot) (1.13.1)
Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /usr/local/lib/python3.11/dist-packages (from numba>=0.49.0->quantecon>=0.7->giddy->splot) (0.43.0)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy->quantecon>=0.7->giddy->splot) (1.3.0)
Downloading esda-2.7.0-py3-none-any.whl (142 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 142.8/142.8 kB 9.1 MB/s eta 0:00:00
Downloading splot-1.1.7-py3-none-any.whl (39 kB)
Downloading giddy-2.3.6-py3-none-any.whl (61 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.3/61.3 kB 4.4 MB/s eta 0:00:00
Downloading spreg-1.8.3-py3-none-any.whl (389 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 389.9/389.9 kB 24.9 MB/s eta 0:00:00
Downloading quantecon-0.8.1-py3-none-any.whl (322 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 322.8/322.8 kB 21.7 MB/s eta 0:00:00
Installing collected packages: quantecon, spreg, esda, giddy, splot
Successfully installed esda-2.7.0 giddy-2.3.6 quantecon-0.8.1 splot-1.1.7 spreg-1.8.3
In [ ]:
!pip install contextily
Collecting contextily
  Downloading contextily-1.6.2-py3-none-any.whl.metadata (2.9 kB)
Requirement already satisfied: geopy in /usr/local/lib/python3.11/dist-packages (from contextily) (2.4.1)
Requirement already satisfied: matplotlib in /usr/local/lib/python3.11/dist-packages (from contextily) (3.10.0)
Collecting mercantile (from contextily)
  Downloading mercantile-1.2.1-py3-none-any.whl.metadata (4.8 kB)
Requirement already satisfied: pillow in /usr/local/lib/python3.11/dist-packages (from contextily) (11.2.1)
Collecting rasterio (from contextily)
  Downloading rasterio-1.4.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (9.1 kB)
Requirement already satisfied: requests in /usr/local/lib/python3.11/dist-packages (from contextily) (2.32.3)
Requirement already satisfied: joblib in /usr/local/lib/python3.11/dist-packages (from contextily) (1.5.1)
Requirement already satisfied: xyzservices in /usr/local/lib/python3.11/dist-packages (from contextily) (2025.4.0)
Requirement already satisfied: geographiclib<3,>=1.52 in /usr/local/lib/python3.11/dist-packages (from geopy->contextily) (2.0)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->contextily) (1.3.2)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib->contextily) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib->contextily) (4.58.4)
Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->contextily) (1.4.8)
Requirement already satisfied: numpy>=1.23 in /usr/local/lib/python3.11/dist-packages (from matplotlib->contextily) (2.0.2)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib->contextily) (24.2)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->contextily) (3.2.3)
Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib->contextily) (2.9.0.post0)
Requirement already satisfied: click>=3.0 in /usr/local/lib/python3.11/dist-packages (from mercantile->contextily) (8.2.1)
Collecting affine (from rasterio->contextily)
  Downloading affine-2.4.0-py3-none-any.whl.metadata (4.0 kB)
Requirement already satisfied: attrs in /usr/local/lib/python3.11/dist-packages (from rasterio->contextily) (25.3.0)
Requirement already satisfied: certifi in /usr/local/lib/python3.11/dist-packages (from rasterio->contextily) (2025.6.15)
Requirement already satisfied: cligj>=0.5 in /usr/local/lib/python3.11/dist-packages (from rasterio->contextily) (0.7.2)
Requirement already satisfied: click-plugins in /usr/local/lib/python3.11/dist-packages (from rasterio->contextily) (1.1.1.2)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests->contextily) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests->contextily) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests->contextily) (2.4.0)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.7->matplotlib->contextily) (1.17.0)
Downloading contextily-1.6.2-py3-none-any.whl (17 kB)
Downloading mercantile-1.2.1-py3-none-any.whl (14 kB)
Downloading rasterio-1.4.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (22.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 22.2/22.2 MB 58.0 MB/s eta 0:00:00
Downloading affine-2.4.0-py3-none-any.whl (15 kB)
Installing collected packages: mercantile, affine, rasterio, contextily
Successfully installed affine-2.4.0 contextily-1.6.2 mercantile-1.2.1 rasterio-1.4.3
In [ ]:
import geopandas as gpd
import pandas as pd
import matplotlib.pyplot as plt
from libpysal.weights import KNN
from esda.moran import Moran, Moran_Local
from splot.esda import moran_scatterplot
In [ ]:
# Variable a analizar
var = 'MedHHInc'  # Puedes cambiarla por 'PCTPOVALL' o 'Ed5CollegePlusPct'
In [ ]:
# Verificar existencia
if var not in datadisMap.columns:
    raise ValueError(f"La columna '{var}' no existe. Revisa: {datadisMap.columns.tolist()}")

# Eliminar valores nulos
datadisMap = datadisMap[~datadisMap[var].isna()]
In [ ]:
# Construir matriz de vecinos con KNN (k=8)
w_knn8 = KNN.from_dataframe(datadisMap, k=8)
w_knn8.transform = 'R'  # Normalizar por filas
In [ ]:
# ---- MORAN GLOBAL ----
moran_global = Moran(datadisMap[var], w_knn8)
print(f"Moran's I: {moran_global.I:.4f}, p-value: {moran_global.p_sim:.4f}")

# Scatterplot de Moran
fig, ax = moran_scatterplot(moran_global, aspect_equal=True)
ax.set_title(f"Moran Scatterplot - {var}")
ax.set_xlabel(f"{var}_std")
ax.set_ylabel(f"SpatialLag_{var}_std")
plt.show()
Moran's I: 0.5577, p-value: 0.0010
No description has been provided for this image
In [ ]:
# ---- MORAN LOCAL (LISA) ----
lisa = Moran_Local(datadisMap[var], w_knn8, seed=1234)

# Clasificación de cuadrantes
datadisMap['quad'] = [q if p < 0.05 else 0 for q, p in zip(lisa.q, lisa.p_sim)]
labels = ['0 no_sig', '1 hotSpot', '2 coldOutlier', '3 coldSpot', '4 hotOutlier']
datadisMap['quad_name'] = [labels[q] for q in datadisMap['quad']]
In [ ]:
# Colores personalizados
from matplotlib import colors
cmap = colors.ListedColormap(['lightgrey', 'red', 'orange', 'blue', 'green'])

# Mapa
fig, ax = plt.subplots(1, 1, figsize=(10, 10))
datadisMap.plot(column='quad_name', cmap=cmap, legend=True, edgecolor='k', linewidth=0.1, ax=ax)
ax.set_title(f"LISA - {var}")
ax.set_axis_off()
plt.show()
No description has been provided for this image
    • Compute the Local Moran for the variables in your data that have significant spatial correlation.
  • Create a new column for each of those variables, with a label ('0 no_sig', '1 hotSpot', '2 coldOutlier', '3 coldSpot', '4 hotOutlier').

  • Prepare a map for each of the variables analyzed, showing the spots and outliers.

In [ ]:
from esda.moran import Moran_Local
from splot.esda import moran_scatterplot
import matplotlib.pyplot as plt
from matplotlib import colors

# Lista de variables a analizar
variables = ['MedHHInc', 'PCTPOVALL', 'Ed5CollegePlusPct']

# Colormap personalizado
my_colors = colors.ListedColormap(['lightgrey', 'red', 'orange', 'blue', 'green'])
labels = ['0 no_sig', '1 hotSpot', '2 coldOutlier', '3 coldSpot', '4 hotOutlier']
In [ ]:
for var in variables:
    print(f"\n---- LISA para {var} ----")

    # Asegurar que no hay NaNs
    data = datadisMap[[var, 'geometry']].dropna()

    # Calcular LISA
    lisa = Moran_Local(data[var], w_knn8, seed=42)

    # Agregar resultados al GeoDataFrame original
    datadisMap[f'{var}_quad'] = [q if p < 0.05 else 0 for q, p in zip(lisa.q, lisa.p_sim)]
    datadisMap[f'{var}_quad_label'] = [labels[q] for q in datadisMap[f'{var}_quad']]

    # Mostrar distribución de categorías
    print(datadisMap[f'{var}_quad_label'].value_counts())

    # Plot
    fig, ax = plt.subplots(1, 1, figsize=(10, 10))
    datadisMap.plot(
        column=f'{var}_quad_label',
        cmap=my_colors,
        categorical=True,
        legend=True,
        edgecolor='k',
        linewidth=0.1,
        ax=ax
    )
    ax.set_title(f'LISA - {var}', fontsize=14)
    ax.set_axis_off()
    plt.show()
---- LISA para MedHHInc ----
MedHHInc_quad_label
0 no_sig         1774
3 coldSpot        622
1 hotSpot         356
2 coldOutlier      41
4 hotOutlier       32
Name: count, dtype: int64
No description has been provided for this image
---- LISA para PCTPOVALL ----
PCTPOVALL_quad_label
0 no_sig         1576
3 coldSpot        671
1 hotSpot         465
4 hotOutlier       68
2 coldOutlier      45
Name: count, dtype: int64
No description has been provided for this image
---- LISA para Ed5CollegePlusPct ----
Ed5CollegePlusPct_quad_label
0 no_sig         1887
3 coldSpot        479
1 hotSpot         324
4 hotOutlier       74
2 coldOutlier      61
Name: count, dtype: int64
No description has been provided for this image
  1. Use your three variables to carry out the cluster/regional analysis.
In [ ]:
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster import hierarchy
from esda import shape as shapestats
from sklearn import metrics
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd

# Variables seleccionadas
vars_cluster = ['Under18Pct2020', 'OwnHomePct', 'FemaleHHPct']
In [ ]:
# 1. Normalizar
scaler = StandardScaler()
X_scaled = scaler.fit_transform(datadisMap[vars_cluster].dropna())

# Nombres de columnas normalizadas
vars_std = [var + '_std' for var in vars_cluster]
datadisMap[vars_std] = X_scaled
In [ ]:
# 2. Dendrograma para ver número de clusters sugeridos
Z = hierarchy.linkage(X_scaled, method='ward')
plt.figure(figsize=(15, 6))
plt.title("Dendrograma - Clustering jerárquico")
hierarchy.dendrogram(Z, leaf_rotation=90., leaf_font_size=6)
plt.show()
No description has been provided for this image
In [ ]:
# 3. Clustering sin restricción espacial
agnes = AgglomerativeClustering(n_clusters=6, linkage='ward')
datadisMap['hc_ag6_other'] = agnes.fit_predict(X_scaled)

# 4. Clustering con restricción espacial (KNN8)
agnes_spatial = AgglomerativeClustering(n_clusters=6, linkage='ward', connectivity=w_knn8.sparse)
datadisMap['hc_ag6_spatial'] = agnes_spatial.fit_predict(X_scaled)
In [ ]:
# 5. Graficar agrupaciones
for col in ['hc_ag6_other', 'hc_ag6_spatial']:
    f, ax = plt.subplots(1, 1, figsize=(10, 10))
    datadisMap.plot(
        column=col,
        categorical=True,
        legend=True,
        ax=ax,
        edgecolor='k',
        linewidth=0.2
    )
    ax.set_title(f'Clusters - {col}', fontsize=14)
    ax.set_axis_off()
    plt.show()
No description has been provided for this image
No description has been provided for this image
In [ ]:
# 6. Comparación de formas de los clusters (Isoperimetric Quotient)
results_shape = {}
for cluster_col in ['hc_ag6_other', 'hc_ag6_spatial']:
    dissolved = datadisMap[[cluster_col, 'geometry']].to_crs(24892).dissolve(by=cluster_col)
    ipq = shapestats.isoperimetric_quotient(dissolved)
    results_shape[cluster_col] = ipq

print("\n Isoperimetric Quotient (compactación):")
print(pd.DataFrame(results_shape))
 Isoperimetric Quotient (compactación):
   hc_ag6_other  hc_ag6_spatial
0      0.003889        0.007647
1      0.002004        0.005633
2      0.002895        0.010802
3      0.001756        0.013998
4      0.003131        0.198662
5      0.007916        0.006903
In [ ]:
# 7. Validación de calidad del clustering
fit_scores = []
for col in ['hc_ag6_other', 'hc_ag6_spatial']:
    ch_score = metrics.calinski_harabasz_score(X_scaled, datadisMap[col])
    sil_score = metrics.silhouette_score(X_scaled, datadisMap[col])
    fit_scores.append((col, ch_score, sil_score))

print("\n📊 Calinski-Harabasz & Silhouette:")
print(pd.DataFrame(fit_scores, columns=['Cluster type', 'CH Score', 'Silhouette']).set_index('Cluster type'))
📊 Calinski-Harabasz & Silhouette:
                  CH Score  Silhouette
Cluster type                          
hc_ag6_other    685.678821    0.166298
hc_ag6_spatial  256.785412    0.032415
  1. Use your three variables to carry out regression analysis (conventional and spatial).
In [ ]:
!pip install pysal
Collecting pysal
  Downloading pysal-25.1-py3-none-any.whl.metadata (15 kB)
Requirement already satisfied: beautifulsoup4>=4.10 in /usr/local/lib/python3.11/dist-packages (from pysal) (4.13.4)
Requirement already satisfied: geopandas>=0.10.0 in /usr/local/lib/python3.11/dist-packages (from pysal) (1.0.1)
Requirement already satisfied: numpy>=1.22 in /usr/local/lib/python3.11/dist-packages (from pysal) (2.0.2)
Requirement already satisfied: packaging>=22 in /usr/local/lib/python3.11/dist-packages (from pysal) (24.2)
Requirement already satisfied: pandas>=1.4 in /usr/local/lib/python3.11/dist-packages (from pysal) (2.2.2)
Requirement already satisfied: platformdirs>=2.0.2 in /usr/local/lib/python3.11/dist-packages (from pysal) (4.3.8)
Requirement already satisfied: requests>=2.27 in /usr/local/lib/python3.11/dist-packages (from pysal) (2.32.3)
Requirement already satisfied: scipy>=1.8 in /usr/local/lib/python3.11/dist-packages (from pysal) (1.15.3)
Requirement already satisfied: shapely>=2.0.1 in /usr/local/lib/python3.11/dist-packages (from pysal) (2.1.1)
Requirement already satisfied: scikit-learn>=1.1 in /usr/local/lib/python3.11/dist-packages (from pysal) (1.6.1)
Requirement already satisfied: libpysal>=4.12.1 in /usr/local/lib/python3.11/dist-packages (from pysal) (4.13.0)
Collecting access>=1.1.9 (from pysal)
  Downloading access-1.1.9-py3-none-any.whl.metadata (2.4 kB)
Requirement already satisfied: esda>=2.6.0 in /usr/local/lib/python3.11/dist-packages (from pysal) (2.7.0)
Requirement already satisfied: giddy>=2.3.6 in /usr/local/lib/python3.11/dist-packages (from pysal) (2.3.6)
Collecting inequality>=1.1.1 (from pysal)
  Downloading inequality-1.1.1-py3-none-any.whl.metadata (3.9 kB)
Collecting pointpats>=2.5.1 (from pysal)
  Downloading pointpats-2.5.1-py3-none-any.whl.metadata (4.7 kB)
Collecting segregation>=2.5.1 (from pysal)
  Downloading segregation-2.5.2-py3-none-any.whl.metadata (2.2 kB)
Collecting spaghetti>=1.7.6 (from pysal)
  Downloading spaghetti-1.7.6-py3-none-any.whl.metadata (12 kB)
Collecting mgwr>=2.2.1 (from pysal)
  Downloading mgwr-2.2.1-py3-none-any.whl.metadata (1.5 kB)
Collecting momepy>=0.9.1 (from pysal)
  Downloading momepy-0.10.0-py3-none-any.whl.metadata (1.5 kB)
Collecting spglm>=1.1.0 (from pysal)
  Downloading spglm-1.1.0-py3-none-any.whl.metadata (3.9 kB)
Collecting spint>=1.0.7 (from pysal)
  Downloading spint-1.0.7.tar.gz (28 kB)
  Preparing metadata (setup.py) ... done
Requirement already satisfied: spreg>=1.8.1 in /usr/local/lib/python3.11/dist-packages (from pysal) (1.8.3)
Collecting tobler>=0.12.1 (from pysal)
  Downloading tobler-0.12.1-py3-none-any.whl.metadata (1.9 kB)
Requirement already satisfied: mapclassify>=2.8.1 in /usr/local/lib/python3.11/dist-packages (from pysal) (2.9.0)
Requirement already satisfied: splot>=1.1.7 in /usr/local/lib/python3.11/dist-packages (from pysal) (1.1.7)
Collecting spopt>=0.6.1 (from pysal)
  Downloading spopt-0.6.1-py3-none-any.whl.metadata (10 kB)
Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.11/dist-packages (from beautifulsoup4>=4.10->pysal) (2.7)
Requirement already satisfied: typing-extensions>=4.0.0 in /usr/local/lib/python3.11/dist-packages (from beautifulsoup4>=4.10->pysal) (4.14.0)
Requirement already satisfied: pyogrio>=0.7.2 in /usr/local/lib/python3.11/dist-packages (from geopandas>=0.10.0->pysal) (0.11.0)
Requirement already satisfied: pyproj>=3.3.0 in /usr/local/lib/python3.11/dist-packages (from geopandas>=0.10.0->pysal) (3.7.1)
Requirement already satisfied: quantecon>=0.7 in /usr/local/lib/python3.11/dist-packages (from giddy>=2.3.6->pysal) (0.8.1)
Requirement already satisfied: matplotlib>=3.6 in /usr/local/lib/python3.11/dist-packages (from inequality>=1.1.1->pysal) (3.10.0)
Requirement already satisfied: networkx>=3.2 in /usr/local/lib/python3.11/dist-packages (from mapclassify>=2.8.1->pysal) (3.5)
Requirement already satisfied: tqdm>=4.65 in /usr/local/lib/python3.11/dist-packages (from momepy>=0.9.1->pysal) (4.67.1)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.4->pysal) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.4->pysal) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.4->pysal) (2025.2)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->pysal) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->pysal) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->pysal) (2.4.0)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->pysal) (2025.6.15)
Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.1->pysal) (1.5.1)
Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.1->pysal) (3.6.0)
Collecting deprecation (from segregation>=2.5.1->pysal)
  Downloading deprecation-2.1.0-py2.py3-none-any.whl.metadata (4.6 kB)
Requirement already satisfied: seaborn in /usr/local/lib/python3.11/dist-packages (from segregation>=2.5.1->pysal) (0.13.2)
Requirement already satisfied: numba in /usr/local/lib/python3.11/dist-packages (from segregation>=2.5.1->pysal) (0.60.0)
Collecting rtree>=1.0 (from spaghetti>=1.7.6->pysal)
  Downloading rtree-1.4.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (2.1 kB)
Collecting pulp>=2.7 (from spopt>=0.6.1->pysal)
  Downloading pulp-3.2.1-py3-none-any.whl.metadata (6.9 kB)
Requirement already satisfied: rasterio in /usr/local/lib/python3.11/dist-packages (from tobler>=0.12.1->pysal) (1.4.3)
Requirement already satisfied: statsmodels in /usr/local/lib/python3.11/dist-packages (from tobler>=0.12.1->pysal) (0.14.4)
Collecting rasterstats (from tobler>=0.12.1->pysal)
  Downloading rasterstats-0.20.0-py3-none-any.whl.metadata (4.2 kB)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.6->inequality>=1.1.1->pysal) (1.3.2)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.6->inequality>=1.1.1->pysal) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.6->inequality>=1.1.1->pysal) (4.58.4)
Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.6->inequality>=1.1.1->pysal) (1.4.8)
Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.6->inequality>=1.1.1->pysal) (11.2.1)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.6->inequality>=1.1.1->pysal) (3.2.3)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.8.2->pandas>=1.4->pysal) (1.17.0)
Requirement already satisfied: sympy in /usr/local/lib/python3.11/dist-packages (from quantecon>=0.7->giddy>=2.3.6->pysal) (1.13.1)
Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /usr/local/lib/python3.11/dist-packages (from numba->segregation>=2.5.1->pysal) (0.43.0)
Requirement already satisfied: affine in /usr/local/lib/python3.11/dist-packages (from rasterio->tobler>=0.12.1->pysal) (2.4.0)
Requirement already satisfied: attrs in /usr/local/lib/python3.11/dist-packages (from rasterio->tobler>=0.12.1->pysal) (25.3.0)
Requirement already satisfied: click>=4.0 in /usr/local/lib/python3.11/dist-packages (from rasterio->tobler>=0.12.1->pysal) (8.2.1)
Requirement already satisfied: cligj>=0.5 in /usr/local/lib/python3.11/dist-packages (from rasterio->tobler>=0.12.1->pysal) (0.7.2)
Requirement already satisfied: click-plugins in /usr/local/lib/python3.11/dist-packages (from rasterio->tobler>=0.12.1->pysal) (1.1.1.2)
Requirement already satisfied: fiona in /usr/local/lib/python3.11/dist-packages (from rasterstats->tobler>=0.12.1->pysal) (1.10.1)
Requirement already satisfied: simplejson in /usr/local/lib/python3.11/dist-packages (from rasterstats->tobler>=0.12.1->pysal) (3.20.1)
Requirement already satisfied: patsy>=0.5.6 in /usr/local/lib/python3.11/dist-packages (from statsmodels->tobler>=0.12.1->pysal) (1.0.1)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy->quantecon>=0.7->giddy>=2.3.6->pysal) (1.3.0)
Downloading pysal-25.1-py3-none-any.whl (17 kB)
Downloading access-1.1.9-py3-none-any.whl (21 kB)
Downloading inequality-1.1.1-py3-none-any.whl (29 kB)
Downloading mgwr-2.2.1-py3-none-any.whl (47 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 47.9/47.9 kB 3.2 MB/s eta 0:00:00
Downloading momepy-0.10.0-py3-none-any.whl (1.7 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.7/1.7 MB 61.0 MB/s eta 0:00:00
Downloading pointpats-2.5.1-py3-none-any.whl (59 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 59.2/59.2 kB 4.8 MB/s eta 0:00:00
Downloading segregation-2.5.2-py3-none-any.whl (141 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 141.6/141.6 kB 11.6 MB/s eta 0:00:00
Downloading spaghetti-1.7.6-py3-none-any.whl (53 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 53.9/53.9 kB 3.9 MB/s eta 0:00:00
Downloading spglm-1.1.0-py3-none-any.whl (41 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 41.4/41.4 kB 2.7 MB/s eta 0:00:00
Downloading spopt-0.6.1-py3-none-any.whl (243 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 243.1/243.1 kB 15.8 MB/s eta 0:00:00
Downloading tobler-0.12.1-py3-none-any.whl (28 kB)
Downloading pulp-3.2.1-py3-none-any.whl (16.4 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 16.4/16.4 MB 68.5 MB/s eta 0:00:00
Downloading rtree-1.4.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (541 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 541.1/541.1 kB 33.7 MB/s eta 0:00:00
Downloading deprecation-2.1.0-py2.py3-none-any.whl (11 kB)
Downloading rasterstats-0.20.0-py3-none-any.whl (17 kB)
Building wheels for collected packages: spint
  Building wheel for spint (setup.py) ... done
  Created wheel for spint: filename=spint-1.0.7-py3-none-any.whl size=31354 sha256=8611e6285a4a8a87b961eb501a999e93bd42382b156c0895d021622134b7e620
  Stored in directory: /root/.cache/pip/wheels/32/dc/2e/400caaa67e697355772a82b77b8c2ac7cd61633f595c477fd8
Successfully built spint
Installing collected packages: rtree, pulp, deprecation, rasterstats, access, tobler, segregation, pointpats, momepy, inequality, spglm, spaghetti, spopt, spint, mgwr, pysal
Successfully installed access-1.1.9 deprecation-2.1.0 inequality-1.1.1 mgwr-2.2.1 momepy-0.10.0 pointpats-2.5.1 pulp-3.2.1 pysal-25.1 rasterstats-0.20.0 rtree-1.4.0 segregation-2.5.2 spaghetti-1.7.6 spglm-1.1.0 spint-1.0.7 spopt-0.6.1 tobler-0.12.1
In [ ]:
!pip install esda splot
Requirement already satisfied: esda in /usr/local/lib/python3.11/dist-packages (2.7.0)
Requirement already satisfied: splot in /usr/local/lib/python3.11/dist-packages (1.1.7)
Requirement already satisfied: geopandas>=0.12 in /usr/local/lib/python3.11/dist-packages (from esda) (1.0.1)
Requirement already satisfied: libpysal>=4.12 in /usr/local/lib/python3.11/dist-packages (from esda) (4.13.0)
Requirement already satisfied: numpy>=1.24 in /usr/local/lib/python3.11/dist-packages (from esda) (2.0.2)
Requirement already satisfied: pandas>1.5 in /usr/local/lib/python3.11/dist-packages (from esda) (2.2.2)
Requirement already satisfied: scikit-learn>=1.2 in /usr/local/lib/python3.11/dist-packages (from esda) (1.6.1)
Requirement already satisfied: scipy>=1.9 in /usr/local/lib/python3.11/dist-packages (from esda) (1.15.3)
Requirement already satisfied: shapely>=2.0 in /usr/local/lib/python3.11/dist-packages (from esda) (2.1.1)
Requirement already satisfied: giddy in /usr/local/lib/python3.11/dist-packages (from splot) (2.3.6)
Requirement already satisfied: mapclassify in /usr/local/lib/python3.11/dist-packages (from splot) (2.9.0)
Requirement already satisfied: matplotlib>=3.3.3 in /usr/local/lib/python3.11/dist-packages (from splot) (3.10.0)
Requirement already satisfied: packaging in /usr/local/lib/python3.11/dist-packages (from splot) (24.2)
Requirement already satisfied: seaborn>=0.11.0 in /usr/local/lib/python3.11/dist-packages (from splot) (0.13.2)
Requirement already satisfied: spreg in /usr/local/lib/python3.11/dist-packages (from splot) (1.8.3)
Requirement already satisfied: pyogrio>=0.7.2 in /usr/local/lib/python3.11/dist-packages (from geopandas>=0.12->esda) (0.11.0)
Requirement already satisfied: pyproj>=3.3.0 in /usr/local/lib/python3.11/dist-packages (from geopandas>=0.12->esda) (3.7.1)
Requirement already satisfied: beautifulsoup4>=4.10 in /usr/local/lib/python3.11/dist-packages (from libpysal>=4.12->esda) (4.13.4)
Requirement already satisfied: platformdirs>=2.0.2 in /usr/local/lib/python3.11/dist-packages (from libpysal>=4.12->esda) (4.3.8)
Requirement already satisfied: requests>=2.27 in /usr/local/lib/python3.11/dist-packages (from libpysal>=4.12->esda) (2.32.3)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (1.3.2)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (4.58.4)
Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (1.4.8)
Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (11.2.1)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (3.2.3)
Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib>=3.3.3->splot) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas>1.5->esda) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas>1.5->esda) (2025.2)
Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.2->esda) (1.5.1)
Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.2->esda) (3.6.0)
Requirement already satisfied: quantecon>=0.7 in /usr/local/lib/python3.11/dist-packages (from giddy->splot) (0.8.1)
Requirement already satisfied: networkx>=3.2 in /usr/local/lib/python3.11/dist-packages (from mapclassify->splot) (3.5)
Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.11/dist-packages (from beautifulsoup4>=4.10->libpysal>=4.12->esda) (2.7)
Requirement already satisfied: typing-extensions>=4.0.0 in /usr/local/lib/python3.11/dist-packages (from beautifulsoup4>=4.10->libpysal>=4.12->esda) (4.14.0)
Requirement already satisfied: certifi in /usr/local/lib/python3.11/dist-packages (from pyogrio>=0.7.2->geopandas>=0.12->esda) (2025.6.15)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.7->matplotlib>=3.3.3->splot) (1.17.0)
Requirement already satisfied: numba>=0.49.0 in /usr/local/lib/python3.11/dist-packages (from quantecon>=0.7->giddy->splot) (0.60.0)
Requirement already satisfied: sympy in /usr/local/lib/python3.11/dist-packages (from quantecon>=0.7->giddy->splot) (1.13.1)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->libpysal>=4.12->esda) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->libpysal>=4.12->esda) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests>=2.27->libpysal>=4.12->esda) (2.4.0)
Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /usr/local/lib/python3.11/dist-packages (from numba>=0.49.0->quantecon>=0.7->giddy->splot) (0.43.0)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from sympy->quantecon>=0.7->giddy->splot) (1.3.0)
In [ ]:
from pysal.model import spreg
from esda.moran import Moran

# Variables independientes y dependiente
dep_var_name = ['Ed1LessThanHSPct']
indep_vars_names = ['Under18Pct2020', 'OwnHomePct', 'FemaleHHPct']
labels = ['% sin secundaria', '% <18 años', '% propietarios', '% jefatura femenina']
In [ ]:
# Verificar que no haya NaNs
datadisMap = datadisMap.dropna(subset=dep_var_name + indep_vars_names)
In [ ]:
# OLS - Regresión Convencional
ols_model = spreg.OLS(
    y=datadisMap[dep_var_name].values,
    x=datadisMap[indep_vars_names].values,
    name_y=labels[0],
    name_x=labels[1:],
    name_ds='datadisMap'
)

print(" OLS - Regresión Lineal Convencional")
print(ols_model.summary)
 OLS - Regresión Lineal Convencional
REGRESSION RESULTS
------------------

SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES
-----------------------------------------
Data set            :  datadisMap
Weights matrix      :        None
Dependent Variable  :% sin secundaria                Number of Observations:        2825
Mean dependent var  :     11.9798                Number of Variables   :           4
S.D. dependent var  :      6.0296                Degrees of Freedom    :        2821
R-squared           :      0.2567
Adjusted R-squared  :      0.2559
Sum squared residual:     76313.1                F-statistic           :    324.7566
Sigma-square        :      27.052                Prob(F-statistic)     :   4.02e-181
S.E. of regression  :       5.201                Log likelihood        :   -8664.577
Sigma-square ML     :      27.013                Akaike info criterion :   17337.154
S.E of regression ML:      5.1975                Schwarz criterion     :   17360.939

------------------------------------------------------------------------------------
            Variable     Coefficient       Std.Error     t-Statistic     Probability
------------------------------------------------------------------------------------
            CONSTANT        -2.52247         1.28995        -1.95547         0.05063
          % <18 años         0.14289         0.03045         4.69321         0.00000
      % propietarios         0.04885         0.01302         3.75171         0.00018
 % jefatura femenina         0.72296         0.02560        28.24597         0.00000
------------------------------------------------------------------------------------

REGRESSION DIAGNOSTICS
MULTICOLLINEARITY CONDITION NUMBER          31.697

TEST ON NORMALITY OF ERRORS
TEST                             DF        VALUE           PROB
Jarque-Bera                       2      16226.454           0.0000

DIAGNOSTICS FOR HETEROSKEDASTICITY
RANDOM COEFFICIENTS
TEST                             DF        VALUE           PROB
Breusch-Pagan test                3        483.023           0.0000
Koenker-Bassett test              3         74.017           0.0000
================================ END OF REPORT =====================================
In [ ]:
#  Moran del residuo del modelo (para ver si hay autocorrelación)
moran_residuals = Moran(ols_model.u, w_knn8)
print(f"\nMoran del error (OLS residuals): I = {moran_residuals.I:.4f}, p = {moran_residuals.p_sim:.4f}")
Moran del error (OLS residuals): I = 0.4102, p = 0.0010
In [ ]:
ser_model = spreg.ML_Error(
    y=datadisMap[dep_var_name].values,
    x=datadisMap[indep_vars_names].values,
    w=w_knn8,
    name_y=labels[0],
    name_x=labels[1:],
    name_w='KNN8',
    name_ds='datadisMap'
)
print("SER - Spatial Error Model")
print(ser_model.summary)
/usr/local/lib/python3.11/dist-packages/spreg/ml_error.py:184: RuntimeWarning: Method 'bounded' does not support relative tolerance in x; defaulting to absolute tolerance.
  res = minimize_scalar(
SER - Spatial Error Model
REGRESSION RESULTS
------------------

SUMMARY OF OUTPUT: ML SPATIAL ERROR (METHOD = full)
---------------------------------------------------
Data set            :  datadisMap
Weights matrix      :        KNN8
Dependent Variable  :% sin secundaria                Number of Observations:        2825
Mean dependent var  :     11.9798                Number of Variables   :           4
S.D. dependent var  :      6.0296                Degrees of Freedom    :        2821
Pseudo R-squared    :      0.2567
Log likelihood      :  -8092.3851
Sigma-square ML     :     16.4431                Akaike info criterion :   16192.770
S.E of regression   :      4.0550                Schwarz criterion     :   16216.555

------------------------------------------------------------------------------------
            Variable     Coefficient       Std.Error     z-Statistic     Probability
------------------------------------------------------------------------------------
            CONSTANT         2.87262         1.11604         2.57394         0.01005
          % <18 años         0.08677         0.03179         2.72965         0.00634
      % propietarios         0.02948         0.01051         2.80395         0.00505
 % jefatura femenina         0.46463         0.02787        16.66935         0.00000
              lambda         0.74535         0.01764        42.25913         0.00000
------------------------------------------------------------------------------------
================================ END OF REPORT =====================================
In [ ]:
lag_model = spreg.ML_Lag(
    y=datadisMap[dep_var_name].values,
    x=datadisMap[indep_vars_names].values,
    w=w_knn8,
    name_y=labels[0],
    name_x=labels[1:],
    name_w='KNN8',
    name_ds='datadisMap'
)

print(" Spatial Lag Model")
print(lag_model.summary)
 Spatial Lag Model
REGRESSION RESULTS
------------------

SUMMARY OF OUTPUT: MAXIMUM LIKELIHOOD SPATIAL LAG (METHOD = FULL)
-----------------------------------------------------------------
Data set            :  datadisMap
Weights matrix      :        KNN8
Dependent Variable  :% sin secundaria                Number of Observations:        2825
Mean dependent var  :     11.9798                Number of Variables   :           5
S.D. dependent var  :      6.0296                Degrees of Freedom    :        2820
Pseudo R-squared    :      0.5456
Spatial Pseudo R-squared:  0.3058
Log likelihood      :  -8083.3486
Sigma-square ML     :     16.6581                Akaike info criterion :   16176.697
S.E of regression   :      4.0814                Schwarz criterion     :   16206.428

------------------------------------------------------------------------------------
            Variable     Coefficient       Std.Error     z-Statistic     Probability
------------------------------------------------------------------------------------
            CONSTANT        -4.70787         1.01334        -4.64591         0.00000
          % <18 años         0.12239         0.02389         5.12251         0.00000
      % propietarios         0.02539         0.01025         2.47745         0.01323
 % jefatura femenina         0.36869         0.02247        16.40901         0.00000
  W_% sin secundaria         0.68105         0.01742        39.08824         0.00000
------------------------------------------------------------------------------------

SPATIAL LAG MODEL IMPACTS
Impacts computed using the 'simple' method.
            Variable         Direct        Indirect          Total
          % <18 años         0.1224          0.2613          0.3837
      % propietarios         0.0254          0.0542          0.0796
 % jefatura femenina         0.3687          0.7873          1.1560
================================ END OF REPORT =====================================
In [ ]:
import matplotlib.pyplot as plt

# Añadir residuos y predicciones al GeoDataFrame
datadisMap["OLS_resid"] = ols_model.u.flatten()
datadisMap["OLS_pred"] = ols_model.predy.flatten()

# Mapa de residuos
fig, ax = plt.subplots(1, 2, figsize=(18, 8))

# Residuos
datadisMap.plot(
    column="OLS_resid",
    cmap="RdBu",
    scheme="quantiles",
    legend=True,
    ax=ax[0],
    edgecolor='black',
    linewidth=0.2
)
ax[0].set_title("🔴 Residuales del Modelo OLS")
ax[0].axis("off")

# Predicciones
datadisMap.plot(
    column="OLS_pred",
    cmap="YlGnBu",
    scheme="quantiles",
    legend=True,
    ax=ax[1],
    edgecolor='black',
    linewidth=0.2
)
ax[1].set_title("🔵 Predicción OLS: % sin secundaria")
ax[1].axis("off")

plt.tight_layout()
plt.show()
/usr/local/lib/python3.11/dist-packages/geopandas/plotting.py:956: UserWarning: Glyph 128308 (\N{LARGE RED CIRCLE}) missing from font(s) DejaVu Sans.
  ax.figure.canvas.draw_idle()
/tmp/ipython-input-98-2524109213.py:36: UserWarning: Glyph 128309 (\N{LARGE BLUE CIRCLE}) missing from font(s) DejaVu Sans.
  plt.tight_layout()
/usr/local/lib/python3.11/dist-packages/IPython/core/pylabtools.py:151: UserWarning: Glyph 128308 (\N{LARGE RED CIRCLE}) missing from font(s) DejaVu Sans.
  fig.canvas.print_figure(bytes_io, **kw)
/usr/local/lib/python3.11/dist-packages/IPython/core/pylabtools.py:151: UserWarning: Glyph 128309 (\N{LARGE BLUE CIRCLE}) missing from font(s) DejaVu Sans.
  fig.canvas.print_figure(bytes_io, **kw)
No description has been provided for this image
In [ ]: